package com.zhengxing.jienci.redis.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 浪遏飞舟
 * @create 2020-06-12 15:51
 * redis各种操作封装
 */
@Component
public class RedisUtils {


    @Autowired
    private RedisTemplate myRedisTemplate;

    private final static Logger LOG = LoggerFactory.getLogger(RedisUtils.class);


    /**
     * 设置过期时间(微秒)
     * @param key 键
     * @param time 过期时间
     * @return
     */
    public boolean expireByMicroseconds(String key,long time){
        return myRedisTemplate.expire(key,time,TimeUnit.MICROSECONDS);
    }



    /**
     * 设置过期时间(毫秒)
     * @param key 键
     * @param time 过期时间
     * @return
     */
    public boolean expireByMilliseconds(String key,long time){
        return myRedisTemplate.expire(key,time,TimeUnit.MILLISECONDS);
    }




    /**
     * 设置过期时间(秒)
     * @param key 键
     * @param time 过期时间
     * @return
     */
    public boolean expireBySeconds(String key,long time){
        return myRedisTemplate.expire(key,time,TimeUnit.SECONDS);
    }



    /**
     * 设置过期时间(分钟)
     * @param key 键
     * @param time 过期时间
     * @return
     */
    public boolean expireByMinutes(String key,long time){
        return myRedisTemplate.expire(key,time,TimeUnit.MINUTES);
    }

    /**
     * 设置过期时间(小时)
     * @param key 键
     * @param time 过期时间
     * @return
     */
    public boolean expireByHours(String key,long time){
        return myRedisTemplate.expire(key,time,TimeUnit.HOURS);
    }

    /**
     * 获得剩余过期时间(秒)
     * @param key 键
     * @return 剩余时间不够一秒为0,没有过期时间为-1,键不存在为-2
     */
    public long getExpireBySeconds(String key){
        return myRedisTemplate.getExpire(key,TimeUnit.SECONDS);
    }


    /**
     * 获得剩余过期时间(分钟)
     * @param key 键
     * @return 剩余时间不够一分钟为0,没有过期时间为-1,键不存在为-2
     */
    public long getExpireByMinutes(String key){
        return myRedisTemplate.getExpire(key,TimeUnit.MINUTES);
    }


    /**
     * 获得剩余过期时间(小时)
     * @param key 键
     * @return 剩余时间不够一小时为0,没有过期时间为-1,,键不存在为-2
     */
    public long getExpireByHours(String key){
        return myRedisTemplate.getExpire(key,TimeUnit.HOURS);
    }


    /**
     * 判断指定的key是否存在
     * @param key 键
     * @return
     */
    public boolean hasKey(String key){
        return myRedisTemplate.hasKey(key);
    }


    /**
     * 删除缓存
     * @param keys 键
     */
    public void delCache(String... keys){
        myRedisTemplate.delete(CollectionUtils.arrayToList(keys));
    }

    /**
     * 获得字符串
     * @param key 键
     * @return
     */
    public Object getStr(String key){
        return myRedisTemplate.opsForValue().get(key);
    }

    /**
     * 放入字符串
     * @param key 键
     * @param value 值
     */
    public void setStr(String key,Object value){
        myRedisTemplate.opsForValue().set(key,value);
    }

    /**
     * 放入字符串并且设置过期时间
     * @param key 键
     * @param value 值
     * @param time 过期时间(秒)
     */
    public void setStr(String key,Object value,long time){
        myRedisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);
    }


    /**
     * 递增(+1)
     * @param key 键
     * @return
     */
    public long incr(String key){
        return myRedisTemplate.opsForValue().increment(key);
    }


    /**
     * 递增
     * @param key 键
     * @param factor 递增数
     * @return
     */
    public long incr(String key,long factor){
        return myRedisTemplate.opsForValue().increment(key,factor);
    }


    /**
     * 递减(-1)
     * @param key 键
     * @return
     */
    public long decr(String key){
        return myRedisTemplate.opsForValue().decrement(key);
    }

    /**
     * 递减
     * @param key 键
     * @param factor 递减数
     * @return
     */
    public long decr(String key,long factor){
        return myRedisTemplate.opsForValue().decrement(key,factor);
    }


    /**
     * 存入list(从队尾添加,如果以前有就覆盖)
     * @param key 键
     * @param list list集合
     * @return list长度
     */
    public Long setListByTail(String key,Object... list){
        delCache(key);
        return myRedisTemplate.opsForList().rightPushAll(key,list);
    }


    /**
     * 存入list(从队尾添加,如果以前有就覆盖)
     * @param key 键
     * @param list list集合
     * @return list长度
     */
    public Long setListByTail(String key,Collection list){
        delCache(key);
        return myRedisTemplate.opsForList().rightPushAll(key,list);
    }



    /**
     * 存入list并且设置过期时间(从队尾添加,如果以前有就覆盖)
     * @param time 过期时间(秒)
     * @param key 键
     * @param list list集合
     * @return list长度
     */
    public Long setListByTailAndExpire(long time,String key,Object... list){
        delCache(key);
        Long count =  myRedisTemplate.opsForList().rightPushAll(key,list);
        myRedisTemplate.expire(key,time,TimeUnit.SECONDS);
        return count;
    }

    /**
     * 存入list(从队尾添加,如果以前有就覆盖)
     * @param time 过期时间(秒)
     * @param key 键
     * @param list list集合
     * @return list长度
     */
    public Long setListByTailAndExpire(String key,Collection list,long time){
        delCache(key);
        Long count = myRedisTemplate.opsForList().rightPushAll(key,list);
        myRedisTemplate.expire(key,time,TimeUnit.SECONDS);
        return count;
    }

    /**
     * 存入list(从队头添加,如果以前有就覆盖)
     * @param key 键
     * @param list 集合
     * @return list长度
     */
    public Long setListByHead(String key,Object... list){
        delCache(key);
        return myRedisTemplate.opsForList().leftPushAll(key,list);
    }

    /**
     * 存入list(从队头添加,如果以前有就覆盖)
     * @param key 键
     * @param list 集合
     * @return list长度
     */
    public Long setListByHead(String key,Collection list){
        delCache(key);
        return myRedisTemplate.opsForList().leftPushAll(key,list);
    }

    /**
     * 往指定key对应的list里面追加元素(从队尾添加)
     * @param key 键
     * @param element 元素
     * @return list长度
     */
    public Long addListByTail(String key,Object... element){
        int i = 0;
        for (Object obj : element){
            if (i < element.length - 1) {
                myRedisTemplate.opsForList().rightPush(key, obj);
            }else {
                return myRedisTemplate.opsForList().rightPush(key, obj);
            }
            i++;
        }
        return 0L;
    }


    /**
     * 往指定key对应的list里面追加元素(从队尾添加)
     * @param key 键
     * @param list 集合
     * @return list长度
     */
    public Long addListByTail(String key,Collection list){
        return myRedisTemplate.opsForList().rightPushAll(key,list);
    }


    /**
     * 往指定key对应的list里面追加元素(从队头添加)
     * @param key 键
     * @param element 元素
     * @return list长度
     */
    public Long addListByHead(String key,Object... element){
        int i = 0;
        for (Object obj : element){
            if (i < element.length - 1) {
                myRedisTemplate.opsForList().leftPush(key, obj);
            }else {
                return myRedisTemplate.opsForList().leftPush(key, obj);
            }
            i++;
        }
        return 0L;
    }

    /**
     * 往指定key对应的list里面追加元素(从队头添加)
     * @param key 键
     * @param list 元素
     * @return list长度
     */
    public Long addListByHead(String key,Collection list){
        return myRedisTemplate.opsForList().leftPushAll(key,list);
    }



    /**
     * 取出指定key的list里面所有的数据(保留数据)
     * @param key 键
     * @return list集合
     */
    public List<Object> getListAll(String key){
        return myRedisTemplate.opsForList().range(key,0,-1);
    }

    /**
     * 取出指定key的list里面的所有数据(保留数据)
     * @param key 键
     * @param start 开始索引(包含本索引元素)
     * @param end 结束索引(包含本索引元素)
     * @return list集合
     */
    public List<Object> getList(String key,long start,long end){
        return myRedisTemplate.opsForList().range(key,start,end);
    }

    /**
     * 获得指定key的list的长度
     * @param key 键
     * @return list长度
     */
    public Long getListSize(String key){
        return myRedisTemplate.opsForList().size(key);
    }

    /**
     * 从队头弹出元素
     * @param key 键
     * @return
     */
    public Object popListByHead(String key){
        return myRedisTemplate.opsForList().leftPop(key);
    }

    /**
     * 从队尾弹出元素
     * @param key 键
     * @return
     */
    public Object popListByTail(String key){
        return myRedisTemplate.opsForList().rightPop(key);
    }


    /**
     * 移除指定个个数的元素
     * @param key 键
     * @param count 个数
     * @param value 值
     * @return 移除的个数
     */
    public Long removeList(String key,long count,Object value){
        return myRedisTemplate.opsForList().remove(key,count,value);
    }

    /**
     * 给list指定索引的元素赋值
     * @param key 键
     * @param index 索引
     * @param value 值
     */
    public void setListByIndex(String key,long index,Object value){
         myRedisTemplate.opsForList().set(key,index,value);
    }


    /**
     * 存入map
     * @param key 键
     * @param data map集合
     */
    public void setMap(String key,Map data){
        myRedisTemplate.opsForHash().putAll(key,data);
    }

    /**
     * 将实体类对象存到缓存
     * @param key
     * @param obj
     */
    public void setBean(String key,Object obj){
        try {
            Map data = BeanUtils.beanToMap(obj);
            myRedisTemplate.opsForHash().putAll(key,data);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 将实体类对象存到缓存
     * @param key
     * @param obj
     */
    public void setMap(String key,Object obj){
        setBean(key,obj);
    }

    /**
     *
     * 存入map并设置过期时间
     * @param key 键
     * @param data map集合
     * @param time 过期时间(秒)
     */
    public void setMapAndExpire(String key,Map data,long time){
        myRedisTemplate.opsForHash().putAll(key,data);
        myRedisTemplate.expire(key,time,TimeUnit.SECONDS);
    }

    /**
     *
     * 存入实体类对象并设置过期时间
     * @param key 键
     * @param bean 实体类对象
     * @param time 过期时间(秒)
     */
    public void setBeanAndExpire(String key,Object bean,long time){
        try {
            Map data = BeanUtils.beanToMap(bean);
            myRedisTemplate.opsForHash().putAll(key, data);
            myRedisTemplate.expire(key, time, TimeUnit.SECONDS);
        }catch (Exception e){
            e.printStackTrace();
        }
    }



    /**
     * 取map数据
     * @param key 键
     * @return 值
     */
    public Map getMap(String key){
        return myRedisTemplate.opsForHash().entries(key);
    }


    /**
     * 获得实体类对象
     * @param key 键
     * @param clazz 实体类Class
     * @return 实体类
     */
    public <T> T getBean(String key,Class<T> clazz){
        try {
            Map data = myRedisTemplate.opsForHash().entries(key);
            return (T)BeanUtils.mapToBean(data, clazz);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 给指定key对应的map添加键值对
     * @param key 键
     * @param mapKey 键
     * @param value 值
     */
    public void setMapValue(String key,String mapKey,String value){
        myRedisTemplate.opsForHash().put(key,mapKey,value);
    }


    /**
     * 获得指定的key的map中的指定key对应的value
     * @param key 键
     * @param mapKey 键
     * @return 值
     */
    public Object getMapValue(String key,String mapKey){
        return myRedisTemplate.opsForHash().get(key,mapKey);
    }
    
    /***********************************************操作set类型**********************************************************/
   
    /**
     * 向set集合中添加元素
     * @param key 键
     * @param value 值
     * @return 值
     */
    public long sadd(String key, String value) {
    	return myRedisTemplate.opsForSet().add(key, value);
    }
    
    /**
     * 将原素value从集合key中剔除出去
     * @param key 键
     * @param value 值
     * @return 值
     */
    public long sdel(String key, String value) {
    	return myRedisTemplate.opsForSet().remove(key, value);
    }
    
    /**
     * 查看value元素是否存在集合中
     * @param key 键
     * @param value 值
     * @return 值
     */
    public boolean isExist(String key, String value) {
    	return myRedisTemplate.opsForSet().isMember(key, value);
    }
    

}
